package com.itcaius.weblog.common.aspect;

import com.itcaius.weblog.common.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Caius
 * @description 实现log的aspect实现类
 * @since Created in 2025-04-16
 */
@Aspect
@Component
@Slf4j
public class ApiOperationLogAspect {

    //自定义对应的切面方法实现使用这个注解的时候直接执行对应的代码
    @Pointcut("@annotation(com.itcaius.weblog.common.aspect.ApiOperationLog)")
    public void apiOperationLog() {}


    /**
     *  环绕
     *
     * @param joinPoint 添加的切点
     * @return 操作实现的对象
     * @throws Throwable 异常处理
     */
    @Around("apiOperationLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        try{
            //开始时间
            long startTime = System.currentTimeMillis();
            //MDC
            MDC.put("traceId", UUID.randomUUID().toString());
            //获取类名以及对应的方法名
            String className = joinPoint.getTarget().getClass().getSimpleName();
            String methodName = joinPoint.getSignature().getName();

            // 请求入参
            Object[] args = joinPoint.getArgs();
            // 入参转json字符串
            String argsJsonStr = Arrays.stream(args).map(toJsonStr()).collect(Collectors.joining(", "));

            //功能描述
            String description = getApiOperationLogDescription(joinPoint);

            log.info("====== 请求开始: [{}], 入参: {}, 请求类: {}, 请求方法: {} =================================== ",
                    description, argsJsonStr, className, methodName);

            //执行切入点方法
            Object result = joinPoint.proceed();

            //计算耗时
            long executionTime = System.currentTimeMillis() - startTime;

            //打印出参相关信息
            log.info("====== 请求结束: [{}], 耗时: {}ms, 出参: {} =================================== ",
                    description, executionTime, JsonUtil.toJsonString(result));

            return result;
        }finally {
            MDC.clear();
        }
    }

    /**
     * 获取注解的描述信息
     * @param joinPoint 切入点
     * @return 切入点的函数的注解描述信息
     */
    private String getApiOperationLogDescription(ProceedingJoinPoint joinPoint){
        //通过ProceedingJoinPoint获取MethodSignature
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();

        //获取method
        Method method = signature.getMethod();

        //通过method获取方法的注解
        ApiOperationLog apiOperationLog = method.getAnnotation(ApiOperationLog.class);

        return apiOperationLog.description();
    }

    /**
     * 实现转换json成为字符串变量
     * @return 返回字符串形式的json数据
     */
    private Function<Object, String> toJsonStr(){
        return args -> JsonUtil.toJsonString(args);
    }
}
